package com.emmmya.ocs.config.security.jwt;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.emmmya.ocs.modules.system.entity.User;
import com.emmmya.ocs.common.constant.RedisConstant;
import com.emmmya.ocs.config.redis.RedisManager;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.thymeleaf.util.StringUtils;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * JWT的token，区分大小写
 */
@Component
@Slf4j
public class JwtConfig {

    @Value("${config.jwt.secret}")
    private String secret;
    @Value("${config.jwt.expire:3600}")
    private long expire;
    @Value("${config.jwt.header}")
    private String header;

    @Autowired
    private RedisManager redisManager;


    private SimpleDateFormat dataformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    /**
     * 生成token
     * @param username
     * @return
     */
    public String createToken (String username){
        //System.out.println(split);
        Date nowDate = new Date();
        log.info("token生效时间："+dataformat.format(nowDate));
        //过期时间
        Date expireDate = new Date(nowDate.getTime() + expire * 1000);
        log.info("token过期时间："+dataformat.format(expireDate));
        return Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setSubject(username)
                .setIssuedAt(nowDate)
                .setExpiration(expireDate)
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();


            //将当前时间的毫秒数和设置的过期时间相加生成一个新的时间
//            Date date = new Date(System.currentTimeMillis()+ (expire * 1000));
//            //由密钥创建一个指定的算法
//            Algorithm algorithm = Algorithm.HMAC256(secret);
//            return JWT.create()
//                    //附带username信息
//                    .withClaim("username",username)
//                    //附带过期时间
//                    .withExpiresAt(date)
//                    //使用指定的算法进行标记
//                    .sign(algorithm);


    }

    /**
     * 获取token中注册信息
     * @param token
     * @return
     */
    public Claims getTokenClaim (String token) {
        try {
            if(!StringUtils.isEmpty(token)||"null".equals(token)) {
                return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
            }else{
                Subject subject = SecurityUtils.getSubject();
                User currentUser = (User) subject.getPrincipal();
                token = (String)redisManager.get(RedisConstant.REDIS_USER_TOKEN + currentUser.getUsername());
                return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
            }
        }
        //捕获这层异常，才能获取到的解析后jwt数据
        catch(ExpiredJwtException e){
            e.printStackTrace();
            return e.getClaims();
        }
        catch (Exception e){
            e.printStackTrace();
            System.out.println("出错了："+token);
            return null;//a
        }
    }
    /**
     * 验证token是否正确
     * @param token 前端传过来的token
     * @param username 用户名
     * @return 返回boolean
     */
    public boolean verify(String token,String username){
        try {
            //获取算法
            Algorithm algorithm = Algorithm.HMAC256(secret);
            //生成JWTVerifier
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim("username",username)
                    .build();
            //验证token
            verifier.verify(token);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 验证token是否过期失效
     * @param expirationTime
     * @return true表示过期，false表示没过期。
     */
    public boolean isTokenExpired (Date expirationTime) {
        return expirationTime.before(new Date());
    }

    /**
     * 获取token失效时间
     * @param token
     * @return
     */
    public Date getExpirationDateFromToken(String token) {
        return getTokenClaim(token).getExpiration();
    }
    /**
     * 获取用户名从token中
     */
    public String getUsernameFromToken(String token) {
        return getTokenClaim(token).getSubject();
    }

    /**
     * 获取jwt发布时间
     */
    public Date getIssuedAtDateFromToken(String token) {
        return getTokenClaim(token).getIssuedAt();
    }

    // --------------------- getter & setter ---------------------

    public String getSecret() {
        return secret;
    }
    public void setSecret(String secret) {
        this.secret = secret;
    }
    public long getExpire() {
        return expire;
    }
    public void setExpire(long expire) {
        this.expire = expire;
    }
    public String getHeader() {
        return header;
    }
    public void setHeader(String header) {
        this.header = header;
    }
}